//Lindsay Ergenekan 
//ergenekl@onid.oregonstate.edu 
//CS311 - 400
//Homework 6 - Twin Primes



//4,294,965,839 - goes up to here
//4,294,967,295 - largest unsigned int

#include "hw5.h"

#define ISBITSET(x,i) ((x[i>>3] & (1<<(i&7)))!=0)
#define SETBIT(x,i) x[i>>3]|=(1<<(i&7));
#define CLEARBIT(x,i) x[i>>3]&=(1<<(i&7))^0xFF;

//#define MAP_SIZE 100000

int main(int argc, char *argv[])
{

    char c;
    long i, j, k;
    pthread_attr_t attr;
    unsigned int maxNumber = UINT_MAX;

  //  unsigned int maxNumber = 5000000;

    unsigned int sq_rt;
    int printPrime = 0; 
    int numThread = 1; 
    unsigned int numCalc = maxNumber; 
    unsigned int MAP_SIZE = ((maxNumber/ 8)) + 1; //set the size to the size of the char

    //checks for printing out primes, 

    numCalc = maxNumber; //set n to UINT_MAX
    printf("numCalc (%lu) Expect \n", numCalc);
    printf("numThread (%d) Expected 2 \n", numThread);
    printf("map_size (%d) Expected  \n", MAP_SIZE);
 //   sleep(5);

    while ((c = getopt(argc, argv, "n:m:p")) != -1)
    switch (c){ 
        case 'n':
            numCalc = atol(optarg); 
            break;
       case 'm':
            numThread = atoi(optarg);
            break;
        case 'p':
            printPrime = 1;
            break;
        }

        printf("numCalc (%lu) \n", numCalc);
        printf("numThread (%lu) \n", numThread);
        printf("printPrime (%lu) \n", printPrime);

////////////////////////////////////variable for the bit map
    unsigned char *bitMAP = (unsigned char *) malloc(MAP_SIZE * sizeof (unsigned char));
    pthread_t thread[numThread]; //variable to track the thread ids
    struct thread_info t_info[numThread]; //variable to pass in the info for sieve funciton 

    SETBIT(bitMAP, 0); //mark off 1 as non-prime

    for (i = 0; i < numThread; ++i)
    {
        printf("In the thread creation \n");
        t_info[i].bitMAP = bitMAP;
        t_info[i].up_to_num = numCalc; 
        pthread_mutex_init(&lock, NULL);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

        if (0 != pthread_create(&thread[i], NULL, sieve, (void*)&t_info[i]))
        {
            printf("Error in thread creation \n");
            exit(2);
        }
    }


  //  sq_rt = sqrt(numCalc);
/*
    printf("sq_rt %d \n", sq_rt);
    SETBIT(flags, 0); //mark off 1 as non-prime

    for(i = 2; i <= sq_rt; i++)
        if(!ISBITSET(flags,i))
            for (j = i*i; j <= 5000; j += i)
                if(!ISBITSET(flags, i)){
                        SETBIT(flags,j); 
                }

*/

  //  sq_rt = sqrt(numCalc);
 //   printf("past the create stage\n");
//////////////////////////////////////////////////////////join all the threads again 
    for (i = 0; i<numThread; ++i){
    
        pthread_join(thread[i], NULL); 
    }
    
 //   printf("past the join stage\n");
 //   sq_rt = sqrt(numCalc);

    for ( i = 3; i < (numCalc-2); ++i ){
        if (!ISBITSET(bitMAP, i) && !ISBITSET(bitMAP,(i+2))){
                printf("PRIME %lu !\n", i);
            }}
    printf("past the print stage \n");


/*
    for ( i = 3; i < (numCalc-2); ++i ){
        if (!ISBITSET(bitMAP, i) ){
                printf("PRIME %lu !\n", i);
            }}
*/

return 0; 
}

/*
void * sieve(void *arg)
{
    pthread_mutex_lock(&lock);

    int i, j, sq_rt;
    int up_to_num; //varialbe to record where to end
    struct thread_info * bitMAP; //set up  the struct varialbe to recevei the argument
    unsigned char * map; //declare the bitmap (map) varible
    bitMAP = (thread_info *) arg; //cast the void * argument to the thread info struct type
    map = bitMAP->bitMAP; //set the bit map 
    up_to_num = bitMAP->up_to_num; //set the number to be read
 //   sq_rt = sqrt(5000);

    printf("up to num %d \n", up_to_num);
    
    pthread_mutex_unlock(&lock);
    pthread_exit((void*)0);//exit the thread

}

*/

/*
void * sieve(void *arg)
{
    pthread_mutex_lock(&lock);

    int i, j;
    long up_to_num, sq_rt; //varialbe to record where to end
    struct thread_info * bitMAP;
    unsigned char * map;
    bitMAP = (thread_info *) arg;
    map = bitMAP->bitMAP;
 //   up_to_num = bitMAP->up_to_num;
 //  sq_rt = sqrt(up_to_num-1);
    up_to_num = 10000;
       sq_rt = sqrt(up_to_num);

    printf("sq_rt %lu \n", up_to_num);
    printf("sq_rt %lu \n", sq_rt);


    for(i = 2; i <= sq_rt; i++)
    {
        if(!ISBITSET(map,i))
        {
            for (j = i*i; j <= sq_rt; j += i)
            {
                if(!ISBITSET(map, i)){
//                    pthread_mutex_lock();
                        SETBIT(map,j); 
//                        printf("set bit (%d) \n", j);
//                    pthread_mutex_unlock();
                }    
            }
        }
    }
        pthread_mutex_unlock(&lock);
        pthread_exit((void*)0);//exit the thread

}
*/

void * sieve(void *arg)
{
    pthread_mutex_lock(&lock);

    long i, j, sq_rt;
    long up_to_num; //varialbe to record where to end
    struct thread_info * bitMAP;
    unsigned char * map;
    bitMAP = (thread_info *) arg;
    map = bitMAP->bitMAP;
    up_to_num = bitMAP->up_to_num;
    sq_rt = sqrt(up_to_num);


  //  printf("sq_rt %d \n", sq_rt);


    for(i = 2; i <= sq_rt; i++)
    {
        if(!ISBITSET(map,i))
        {
            for (j = i*i; j <= up_to_num; j += i)
            {
                if(!ISBITSET(map, i)){
//                    pthread_mutex_lock();
                        SETBIT(map,j); 
//                    pthread_mutex_unlock();
                }    
            }
        }
    }
        pthread_mutex_unlock(&lock);
        pthread_exit((void*)0);//exit the thread

}

